/*
 * bot.cpp
 *
 *  Created on: Nov 27, 2013
 *      Author: killerg
 */

#include "robot_deps.h"

#include "bot.h"
#include "bots.h"

#include "share/cl_msg.pb.h"
#include "share/cs_msg.pb.h"
#include "share/sl_msg.pb.h"
#include "share/msg.h"
#include "share/json/json.h"
#include "share/util.h"
#include "share/clock.h"
#include "share/msg_handler.h"
#include "share/patterns.h"

const char* ServerStageName[] = {
        "LErr",
        "SErr",
        "Idle",
        "LIni",
        "LCon",
        "LAut",
        "LReg",
        "LLst",
        "LSel",
        "SIni",
        "SCon",
        "SLod",
        "SCre",
        "SPly",
};



bool bot_t::init(const arg_t &arg) {
    this->arg = arg;
    this->stage = EIdle;


    this->mailindex = 0;
    this->mail_timer = 0.0f;
    this->try_interval = 1.0f;
    this->play_timer = random(arg.min_play_sec, arg.max_play_sec);
    this->echo_timer = random(arg.min_interval, arg.max_interval) / 1000.0f;

    if (!net.init(arg.base, g_bots.code_cb)) {
        return false;
    }

    return true;
}
void bot_t::destroy() {
    net.destroy();
}
void bot_t::update() {
    switch (stage) {
        case EErrorServer:
			if (account) {
				g_bots.accounts.push(account);
				account = NULL;
			}
            if (net.is_connected())
                net.disconnect();
            break;
        case EErrorLogon:
			if (account) {
				g_bots.accounts.push(account);
				account = NULL;
			}
            if (net.is_connected())
                net.disconnect();
			break;
        case EIdle:
            if (g_bots.remain_conning >= 0) {
                --g_bots.remain_conning;
                stage = ELogonInit;
    			if (account) {
    				g_bots.accounts.push(account);
    				account = NULL;
    			}
    			account = g_bots.accounts.front();
    			g_bots.accounts.pop();
    			machinecode = random(0, g_bots.botnum);
            }
            break;
        case ELogonInit:
            {
                if (net.is_connected())
                    break;
                if (net.is_connecting())
                    break;

                bool ret = net.connect(
                        arg.logon_addr.c_str(),
                        false,
                        [this](){
                            Json::Value json;
                            json["account"] = account->account;
                            json["passwd"] = account->passwd;
                            json["step"] = "auth";
                            CREATE_CL_CMSG(CAuth, auth);
                            auth->set_json(to_cstr(json));
                            auth->set_epid(co::EPI_au);
                            net.send(___msg);

                            stage = ELogonAuthing;
                        },
                        [this](){
                            stage = EIdle;
                        },
                        [this](){
                            stage = EErrorLogon;
                        }
                        );
                stage = ret ? ELogonConnecting : EErrorLogon;
            }

            break;
        case ELogonConnecting: break;
        case ELogonAuthing: break;
        case ELogonRegistering: break;
        case ELogonGettingList: break;
        case ELogonSelecting: break;
        case EServerInit:
            {
                if (net.is_connected())
                    break;
                if (net.is_connecting())
                    break;

                bool ret = net.connect(
                        data.server_addr.c_str(),
                        false,
                        [this](){
                            CREATE_CS_CMSG(CLoad, load);
                            load->set_playerid(data.playerid);
                            load->set_key(data.key);
                            net.send(___msg);
                            stage = EServerLoading;
                        },
                        [this](){
                            stage = EIdle;
                        },
                        [this](){
                            stage = EErrorServer;
                        }
                        );

                stage = ret?EServerConnecting:EErrorServer;
            }
            break;
        case EServerConnecting: break;
        case EServerLoading: break;
        case EServerCreating: break;
        case EServerPlaying:
            {
                echo_timer -= g_bots.clock->delta;
                if (echo_timer <= 0.0f) {
                    echo_timer = random(arg.min_interval, arg.max_interval) / 1000.0f;
                	if (g_bots.botnum > 1) {
                    	CREATE_CS_CMSG(CChat, chat);
    					chat->set_channel(cs::ECC_World);
    					int len = random(arg.min_packet, arg.max_packet);
    					std::stringstream ss;
    					for (int i=0; i<len; ++i) {
    						ss << char('0' + i % 10);
    					}
    					chat->set_content(ss.str());
    					net.send(___msg);

                	} else {
                        CREATE_CS_CMSG(CEcho, echo);
                        auto oecho = echo->mutable_echo();
                        int len = random(arg.min_packet, arg.max_packet);
                        std::stringstream ss;
                        for (int i=0; i<len; ++i) {
                            ss << char('0' + i % 10);
                        }
                        oecho->set_str(ss.str());
                        oecho->set_stamp(g_bots.clock->eclipse);
                        net.send(___msg);
                	}

                }

                if (mailindex < 3) {
                    mail_timer -= g_bots.clock->delta;
                    if (mail_timer <= 0.0f) {
                        mail_timer = random(2, 4);

                        ++mailindex;
                        int64_t serverpart = (data.playerid / co::MaxAccountNum) * co::MaxAccountNum;
                        int64_t receiverid = serverpart + g_bots.startid + (account->id + mailindex - g_bots.startid) % g_bots.botnum;

                        CREATE_CS_CMSG(CMailSend, mailsend);
                        mailsend->set_receiver(receiverid);
                        mailsend->set_content(fmt_cstr("from %s", account->account.c_str()));
                        net.send(___msg);
                    }
                }


                play_timer -= g_bots.clock->delta;
                if (play_timer <= 0.0f) {
                    play_timer = random(arg.min_play_sec, arg.max_play_sec);
                    net.disconnect();
                }
                stat.play_timer = play_timer;
            }
            break;
        default:
            break;

    }

    if (net.is_connected()) {
        switch (stage) {
        case ELogonConnecting:  case ELogonAuthing:
        case ELogonRegistering: case ELogonGettingList:
        case ELogonSelecting:
            update_lmsg();
            break;
        case EServerConnecting: case EServerLoading:
        case EServerCreating:   case EServerPlaying:
            update_smsg();
            break;
        }
    }

    net.update();
}

std::string echo_static_t::get_str() {
    char buffer[1024];
    double avg = num == 0?0:(latency_all / num);
    sprintf(buffer,
            "tmr:%-.6f "
            "avg:%-.6f "
            "min:%-.6f "
            "max:%-.6f "
            "all:%-.6f "
            "num:%-6d ",
            play_timer,
            avg,
            latency_min,
            latency_max,
            latency_all,
            num
            );

    return buffer;
}
